#include "widget_helper_win32.h"
#include "widget.h"
#include "widget_win32.h"
#include <windows.h>
#include <iostream>

using namespace krryn::gui;
using namespace krryn::system_imp;

// Enable visual styles
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

widget_win32 *widget_hook_win32::m_Widget = 0;
HHOOK widget_hook_win32::m_Hook = 0;

widget_hook_win32::widget_hook_win32(widget_win32 *a_Widget){
	if(m_Widget || m_Hook){
		throw std::runtime_error("Can't create window at this time (window hook still in progress)");
	}

	m_Widget = a_Widget;
	m_Hook = ::SetWindowsHookEx(
		WH_CBT, widget_hook_win32::proc, NULL, ::GetCurrentThreadId());

	if(!m_Hook){
		throw std::runtime_error("Can't hook window");
	}
}

widget_hook_win32::~widget_hook_win32(){
	//! FIXME: Sometimes proc() is called after the destructor

	/*if(m_Hook){
		::UnhookWindowsHookEx(m_Hook);
	}

	m_Widget = 0;*/
}

LRESULT CALLBACK widget_hook_win32::proc(int code, WPARAM wParam, LPARAM lParam){
	if(code == HCBT_CREATEWND){
		HWND hWnd = (HWND)wParam;

		if(m_Widget){
			m_Widget->attach(hWnd);

			m_Widget->set_old_proc(
				(WNDPROC)(LONG_PTR)::SetWindowLongPtr(
				hWnd, GWL_WNDPROC, (LONG_PTR) widget_win32::proc));

			if(!::UnhookWindowsHookEx(m_Hook)){
				throw std::runtime_error("Can't unhook window");
			}else{
				m_Hook = 0;
				m_Widget = 0;
			}
		}

		return 0;
	}

	return ::CallNextHookEx(m_Hook, code, wParam, lParam);
}

HFONT widget_helper_win32::fix_font(HWND a_hWnd)
{
	LOGFONT lf;
	HFONT font;

	::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0);
	font = ::CreateFontIndirect(&lf);

	SendMessage(a_hWnd, WM_SETFONT, (WPARAM)font, TRUE);
	return font;
}

void widget_helper_win32::load_common_controls(){
	static bool l_Loaded = false;

	if(!l_Loaded)
	{
		INITCOMMONCONTROLSEX l_Ctrl;
		// simply load all of the common controls :-)
		l_Ctrl.dwSize = sizeof(INITCOMMONCONTROLSEX);
		l_Ctrl.dwICC = ICC_ANIMATE_CLASS
					| ICC_BAR_CLASSES
					| ICC_COOL_CLASSES
					| ICC_DATE_CLASSES
					| ICC_HOTKEY_CLASS
					| ICC_INTERNET_CLASSES
					| ICC_LINK_CLASS
					| ICC_LISTVIEW_CLASSES
					| ICC_NATIVEFNTCTL_CLASS
					| ICC_PAGESCROLLER_CLASS
					| ICC_PROGRESS_CLASS
					| ICC_STANDARD_CLASSES
					| ICC_TAB_CLASSES
					| ICC_TREEVIEW_CLASSES
					| ICC_UPDOWN_CLASS
					| ICC_USEREX_CLASSES
					| ICC_WIN95_CLASSES;

		BOOL l_Success = InitCommonControlsEx(&l_Ctrl);
		
		if(!l_Success){
			std::clog << "Failed to load common controls" << std::endl;
		}

		l_Loaded = true;
	}
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
	return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

char * widget_helper_win32::window_class(){
	static bool m_IsRegistered = false;

	if(!m_IsRegistered){
		WNDCLASS l_WindowClass;
		memset(&l_WindowClass, 0, sizeof(l_WindowClass));

		l_WindowClass.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
		l_WindowClass.lpfnWndProc	= (WNDPROC)WindowProc;
		l_WindowClass.hIcon			= LoadIcon(NULL, IDI_WINLOGO);
		l_WindowClass.hCursor		= LoadCursor(NULL, IDC_ARROW);
		l_WindowClass.hbrBackground	= (HBRUSH)(COLOR_BTNFACE+1);
		l_WindowClass.lpszClassName	= "krryn::window_class";

		if(!RegisterClass(&l_WindowClass)){
			throw widget_exception("Can't register window class");
		}else{
			m_IsRegistered = true;
		}
	}

	return "krryn::window_class";
}
